﻿Public Class ProjectControl
    Private MilestoneBaseColor As Drawing.Color = Drawing.Color.LightBlue
    Private MilestoneDapColor As Drawing.Color = Drawing.Color.LightYellow
    Private MilestoneSopColor As Drawing.Color = Drawing.Color.Red
    Private BaseColor As New System.Drawing.SolidBrush(Drawing.Color.Black)
    Private BaseSecondaryColor As New System.Drawing.SolidBrush(Drawing.Color.LightGray)
    Private SelectionColor As New System.Drawing.SolidBrush(Drawing.Color.LightBlue)
    Private StdBackColor As New System.Drawing.SolidBrush(Drawing.Color.White)
    Private StdLightBrush As New Drawing.SolidBrush(Drawing.Color.AliceBlue)
    Private StdBoldBrush As New Drawing.SolidBrush(Drawing.Color.LightBlue)
    Private YearLinePen As New System.Drawing.Pen(BaseColor, 1)
    Private MonthLinePen As New System.Drawing.Pen(BaseSecondaryColor, 1)
    Private LightBasePen As New System.Drawing.Pen(BaseColor, 1)
    Private BoldBasePen As New System.Drawing.Pen(BaseColor, 2)
    Private BoldSelectionPen As New System.Drawing.Pen(SelectionColor, 2)

    Private HiRefresh As Integer = 10
    Private StdRefresh As Integer = 70
    Private LowRefresh As Integer = 500

    Private Const ScrollBarWidth As Integer = 20
    Private Const ScrollBarHeight As Integer = 20
    Private Const YearDefaultWidth As Integer = 600
    Private Const DateStripHeight As Integer = 20

    Private DragOperationStarted As Boolean = False
    Private TranslateElement As Boolean = False
    Private DragObjectValue As Object
    Private BufferedMousePosition As System.Drawing.Point
    Private pYearsBackOffset As Integer = 0
    Private WithEvents ProjectEditor As New L3DObjectsLibrary.ProjectEditor
    Private WithEvents CarEditor As New L3DObjectsLibrary.CarEditor With {.Visible = False, .Parent = Me}
    Private WithEvents MilestoneEditor As New L3DObjectsLibrary.MilestoneEditor With {.Visible = False, .Parent = Me}
    Private WithEvents ElementEditor As New L3DObjectsLibrary.ProjectElementEditor With {.Visible = False, .Parent = Me}
    Private ZoomFactorValue As Single = 1
    Private WithEvents ProjectValue As Project
    Private WithEvents UndoHistoryValue As New PowerCollection(Of Project)
    Private UndoHistoryPositionValue As Integer
    Public Event UndoRedoPerformed(ByVal sender As Object, ByVal UndoRedo As UndoRedoValue)
    Public Event QueryChange(ByVal sender As Object, ByVal e As QueryChangeEventArgs)

#Region "PROPERTIES DEFINITION"
    Public Property Project As Project
        Get
            Return ProjectValue
        End Get
        Set(ByVal value As Project)
            ProjectValue = value
        End Set
    End Property
    Public ReadOnly Property UndoHistory As PowerCollection(Of Project)
        Get
            Return UndoHistoryValue
        End Get
    End Property
    Public Property UndoHistoryPosition As Integer
        Get
            Return UndoHistoryPositionValue
        End Get
        Set(ByVal value As Integer)
            UndoHistoryPositionValue = value
        End Set
    End Property
    Public ReadOnly Property ActiveRectangle As System.Drawing.Rectangle
        Get
            Dim Loc As New Drawing.Point(Padding.Top, Padding.Left)
            Dim Siz As New Drawing.Size(Width - Padding.Left - Padding.Right, Height - Padding.Top - Padding.Bottom)
            Dim Result As New Drawing.Rectangle(Loc, Siz)
            Return Result
        End Get
    End Property
    Public ReadOnly Property ScrollOffset As Drawing.Point
        Get
            Dim Result As New Drawing.Point(HScrollBar.Value, VScrollBar.Value)
            Return Result
        End Get
    End Property
    Public Property ZoomFactor As Single
        Get
            Return ZoomFactorValue
        End Get
        Set(ByVal value As Single)
            ZoomFactorValue = value
        End Set
    End Property
    Private ReadOnly Property YearWidth As Single
        Get
            Dim Result As Single = YearDefaultWidth * ZoomFactor
            Return Result
        End Get
    End Property
    Private ReadOnly Property MonthWidth As Single
        Get
            Dim Result As Single = YearWidth / 12
            Return Result
        End Get
    End Property
    Public ReadOnly Property PixelsLenghtPerDay As Single
        Get
            Dim Days As Single
            Days = YearWidth / 365
            Return Days
        End Get
    End Property
    Public ReadOnly Property Editor As L3DObjectsLibrary.ProjectEditor
        Get
            Return ProjectEditor
        End Get
    End Property
    Public Property EditMode As Boolean
        Get
            Return Editor.Visible
        End Get
        Set(ByVal value As Boolean)
            Editor.Visible = value
            If value = True Then
                Editor.FillFromLinkedProject()
            End If
        End Set
    End Property
    Public ReadOnly Property NumberOfYears As Integer
        Get
            Return HScrollBar.Maximum / YearWidth
        End Get
    End Property
    Public ReadOnly Property RMP As Drawing.Point
        Get
            Dim Result As Drawing.Point = Me.PointToClient(MousePosition)
            Return Result
        End Get
    End Property
#End Region
#Region "METHODS"
    Private Function GetElementIndex(ByVal Point As System.Drawing.Point, Optional ByVal FullWidth As Boolean = False) As Integer
        Dim Result As Integer = -1
        Dim TopPosition As Integer = L3DObjectsLibrary.L3DGraphics.FirstElementVerticalPosition
        For Each Element In Project.ProjectElements
            Dim TargetRect As System.Drawing.Rectangle = GetElementRectangle(Element)
            If TargetRect.Contains(Point) = True Then
                Result = Project.ProjectElements.IndexOf(Element)
                Exit For
            ElseIf FullWidth = True And Point.Y > TargetRect.Top And Point.Y < TargetRect.Bottom Then
                Result = Project.ProjectElements.IndexOf(Element)
                Exit For
            End If
        Next
        Return Result
    End Function
    Private Function GetGroupIndex(ByVal Point As System.Drawing.Point, Optional ByVal FullWidth As Boolean = False) As Integer
        Dim Result As Integer = -1
        Dim GRect As System.Drawing.Rectangle
        Dim ElementIndex As Integer = GetElementIndex(Point, True)
        If ElementIndex > -1 Then
            Dim TargetElement As L3DObjectsLibrary.ProjectElement = Project.ProjectElements(ElementIndex)
            For Each Group As L3DObjectsLibrary.Group In TargetElement.Groups
                GRect = GetGroupRectangle(Group)
                If GRect.Contains(Point) Then
                    Result = TargetElement.Groups.IndexOf(Group)
                    Exit For
                ElseIf FullWidth = True And Point.Y > GRect.Top And Point.Y < GRect.Bottom Then
                    Result = TargetElement.Groups.IndexOf(Group)
                    Exit For
                End If
            Next
        End If
        Return Result
    End Function
    Private Function GetCarIndex(ByVal Point As System.Drawing.Point) As Integer
        Dim Result As Integer = -1
        Dim ElementIndex As Integer = GetElementIndex(Point, True)
        If ElementIndex > -1 Then
            Dim GroupIndex As Integer = GetGroupIndex(Point, True)
            If GroupIndex > -1 Then
                Dim TargetGroup As L3DObjectsLibrary.Group = Project.ProjectElements(ElementIndex).Groups(GroupIndex)
                For Each Car As L3DObjectsLibrary.Car In TargetGroup.Cars
                    Dim TargetCarRectangle As System.Drawing.Rectangle = GetCarRectangle(Car)
                    If TargetCarRectangle.Contains(Point) Then
                        Result = TargetGroup.Cars.IndexOf(Car)
                    End If
                Next
            End If
        End If
        Return Result
    End Function
    Private Function GetObjectUnderPoint(ByVal Point As System.Drawing.Point) As DragDropStructure
        Dim Result As New DragDropStructure
        Dim ElementIndex As Integer = GetElementIndex(Point)
        Dim CarIndex As Integer = GetCarIndex(Point)
        Dim GroupIndex As Integer = GetGroupIndex(Point)
        With Result
            .Project = Project
            .LowestLevelObject = DragDropStructure.LowestLevelValues.Project
            If ElementIndex > -1 Then
                .LowestLevelObject = DragDropStructure.LowestLevelValues.Element
                .Element = Project.ProjectElements(ElementIndex)
            ElseIf GroupIndex > -1 Then
                ElementIndex = GetElementIndex(Point, True)
                If ElementIndex > -1 Then
                    .Element = Project.ProjectElements(ElementIndex)
                End If
            End If
            If ElementIndex > -1 And GroupIndex > -1 Then
                .LowestLevelObject = DragDropStructure.LowestLevelValues.Group
                .Group = .Element.Groups(GroupIndex)
                If CarIndex > -1 Then
                    .Car = .Group.Cars(CarIndex)
                    .LowestLevelObject = DragDropStructure.LowestLevelValues.Car
                End If
            End If
        End With
        Return Result
    End Function
    Private Function ComputeLeftOnDate(ByVal MyDate As Date) As Integer
        Dim TargetY As Integer = MyDate.Year
        Dim Result As Integer = YearWidth * Math.Abs(Project.FirstProjectYear - TargetY)
        Result = Result + MyDate.DayOfYear * YearWidth / 365
        Result = Result - ScrollOffset.X
        Return Result
    End Function
    Private Function ComputeDateOnLeft(ByVal LeftValue As Integer) As Date
        Dim FirstDate As Date = CDate("01/01/" & Str(Project.FirstProjectYear()))
        Dim Days As Integer = (LeftValue + ScrollOffset.X) / PixelsLenghtPerDay
        Return DateAdd(DateInterval.Day, Days, FirstDate)
    End Function
    Private Function ComputeElementLocation(ByVal Element As L3DObjectsLibrary.ProjectElement) As Drawing.Point
        Dim Result As Drawing.Point
        If Element.ElementType = ElementTypeValue.L3DMixed Or Element.ElementType = ElementTypeValue.L3DPhase Then
            Result.X = ComputeLeftOnDate(Element.ElementRealStartDate)
        ElseIf Element.ElementType = ElementTypeValue.L3DMilestone Then
            Dim Milestone As L3DObjectsLibrary.Milestone = Element.Milestones.First
            Result.X = ComputeLeftOnDate(Element.ElementRealStartDate) - L3DObjectsLibrary.L3DGraphics.MilestoneWidth / 2
        Else
            Result.X = 0
        End If
        Result.Y = L3DObjectsLibrary.L3DGraphics.FirstElementVerticalPosition - ScrollOffset.Y
        Dim ElHeight As Integer
        Dim ElInd As Integer
        If Project.ProjectElements.IndexOf(Element) > -1 Then
            Do Until ElInd = Project.ProjectElements.IndexOf(Element)
                ElHeight = ComputeElementSize(Project.ProjectElements(ElInd)).Height
                If ElHeight > 0 Then
                    ElHeight = ElHeight + L3DObjectsLibrary.L3DGraphics.ElementDistance
                End If
                Result.Y = Result.Y + ElHeight
                ElInd = ElInd + 1
            Loop
        End If
        Return Result
    End Function
    Private Function ComputeElementSize(ByVal Element As L3DObjectsLibrary.ProjectElement) As Drawing.Size
        Dim Result As Drawing.Size
        If Element.ElementType = ElementTypeValue.L3DMixed Or Element.ElementType = ElementTypeValue.L3DPhase Then
            Result.Width = ComputeLeftOnDate(Element.ElementRealEndDate) - ComputeLeftOnDate(Element.ElementRealStartDate)
        ElseIf Element.ElementType = ElementTypeValue.L3DMilestone Then
            Result.Width = L3DObjectsLibrary.L3DGraphics.MilestoneWidth
        Else
            Result.Width = 0
        End If
        If Element.ElementType = ElementTypeValue.L3DMixed Or Element.ElementType = ElementTypeValue.L3DPhase Then
            Result.Height = Element.Groups.Count * (L3DObjectsLibrary.L3DGraphics.GroupHeight + L3DObjectsLibrary.L3DGraphics.GroupDistance) + 2 * L3DObjectsLibrary.L3DGraphics.GroupDistance + L3DObjectsLibrary.L3DGraphics.ElementNameHeight
        ElseIf Element.ElementType = ElementTypeValue.L3DMilestone Then
            If Element.Milestones.First.ShowInPlan = True Then
                Result.Height = L3DObjectsLibrary.L3DGraphics.MilestoneHeight
            End If
        End If
        Return Result
    End Function
    Private Sub MakeEditorsInvisible()
        If CarEditor.Visible Then CarEditor.Visible = False
        If ElementEditor.Visible Then ElementEditor.Visible = False
        If MilestoneEditor.Visible Then MilestoneEditor.Visible = False
        If EditMode Then EditMode = False
    End Sub
    Private Sub AddRemoveProjectHandlers(ByVal AddRemove As AddRemove)
        For Each Pr As Project In UndoHistory
            RemoveHandler Pr.QueryChange, AddressOf Project_QueryChange
            AddHandler Project.QueryChange, AddressOf Project_QueryChange
        Next
        'Select Case AddRemove
        '    Case AddRemove.Add
        '        AddHandler Project.QueryChange, AddressOf Project_QueryChange
        '    Case AddRemove.Remove
        '        RemoveHandler Project.QueryChange, AddressOf Project_QueryChange
        'End Select
    End Sub

#End Region

#Region "DRAGDROP MANAGEMENT"
    Private Sub DropDragDropStructure(ByVal Source As DragDropStructure)
        Dim Destination As DragDropStructure = GetObjectUnderPoint(RMP)
        Dim GroupDestination As L3DObjectsLibrary.Group
        Dim ElementDestination As L3DObjectsLibrary.ProjectElement
        If TranslateElement = True Then
            MakeUndoPoint(UndoType.ElEdit)
            Dim El As ProjectElement = Source.Element
            Dim HorDiff As Integer = RMP.X - BufferedMousePosition.X
            Dim NewDate As Date = ComputeDateOnLeft(ComputeLeftOnDate(El.ElementRealStartDate) + HorDiff)
            Dim Days As Integer = DateDiff(DateInterval.Day, El.ElementRealStartDate, NewDate)
            El.Translate(Days)
            If El.MilestoneSpecialID = SpecialIDValues.DAP Then Project.ProjectDAPDate = El.ElementStartDate
            If El.MilestoneSpecialID = SpecialIDValues.SOP Then Project.ProjectSOPDate = El.ElementStartDate
            TranslateElement = False
            Exit Sub
        End If
        Select Case Destination.LowestLevelObject
            Case DragDropStructure.LowestLevelValues.Element
                ElementDestination = Destination.Element
                Select Case Source.LowestLevelObject
                    Case DragDropStructure.LowestLevelValues.Car
                        If ElementDestination.ElementType = ElementTypeValue.L3DPhase Or ElementDestination.ElementType = ElementTypeValue.L3DMixed Then
                            If Destination.Element.Groups.First.Cars.Contains(Source.Car) = False Then
                                MakeUndoPoint(UndoType.CarMove)
                                GroupDestination = ElementDestination.Groups.First
                                GroupDestination.Cars.Add(Source.Car)
                                Source.Group.Cars.RemoveAt(Source.Group.Cars.IndexOf(Source.Car))
                            End If
                        Else
                            Exit Sub
                        End If
                    Case DragDropStructure.LowestLevelValues.Group
                        If ElementDestination.ElementType = ElementTypeValue.L3DPhase Or ElementDestination.ElementType = ElementTypeValue.L3DMixed Then
                            If Destination.Element.Groups.Contains(Source.Group) = False Then
                                MakeUndoPoint(UndoType.GroupMove)
                                ElementDestination.Groups.Add(Source.Group)
                                Source.Element.Groups.RemoveAt(Source.Element.Groups.IndexOf(Source.Group))
                            End If
                        Else
                            Exit Sub
                        End If
                    Case DragDropStructure.LowestLevelValues.Element
                        If Source.Element IsNot Destination.Element Then
                            MakeUndoPoint(UndoType.ElMove)
                            Project.ProjectElements.ExchangeIndex(GetElementIndex(Me.PointToClient(MousePosition)), Project.ProjectElements.IndexOf(Source.Element))
                        End If
                End Select
            Case DragDropStructure.LowestLevelValues.Group
                GroupDestination = Destination.Group
                Select Case Source.LowestLevelObject
                    Case DragDropStructure.LowestLevelValues.Car
                        If Destination.Group.Cars.Contains(Source.Car) = False Then
                            MakeUndoPoint(UndoType.CarMove)
                            GroupDestination.Cars.Add(Source.Car)
                            Source.Group.Cars.RemoveAt(Source.Group.Cars.IndexOf(Source.Car))
                        End If
                    Case DragDropStructure.LowestLevelValues.Group
                        If Destination.Group IsNot Source.Group Then
                            MakeUndoPoint(UndoType.GroupMove)
                            If Source.Element Is Destination.Element Then
                                Destination.Element.Groups.ExchangeIndex(Source.Element.Groups.IndexOf(Destination.Group), Source.Element.Groups.IndexOf(Source.Group))
                            Else
                                Destination.Element.Groups.Add(Source.Group)
                                Source.Element.Groups.RemoveAt(Source.Element.Groups.IndexOf(Source.Group))
                            End If
                        End If
                    Case DragDropStructure.LowestLevelValues.Element
                        If Destination.Element IsNot Source.Element Then
                            MakeUndoPoint(UndoType.ElMove)
                            Project.ProjectElements.ExchangeIndex(GetElementIndex(RMP), Project.ProjectElements.IndexOf(Source.Element))
                        End If
                End Select
            Case DragDropStructure.LowestLevelValues.Car
                GroupDestination = Destination.Group
                Select Case Source.LowestLevelObject
                    Case DragDropStructure.LowestLevelValues.Car
                        If Destination.Car IsNot Source.Car Then
                            MakeUndoPoint(UndoType.CarMove)
                            If Source.Group Is Destination.Group Then
                                GroupDestination.Cars.ExchangeIndex(GetCarIndex(RMP), Source.Group.Cars.IndexOf(Source.Car))
                            Else
                                GroupDestination.Cars.Add(Source.Car)
                                Source.Group.Cars.RemoveAt(Source.Group.Cars.IndexOf(Source.Car))
                            End If
                        End If
                    Case DragDropStructure.LowestLevelValues.Group
                        If Destination.Element.Groups.Contains(Source.Group) = False Then
                            MakeUndoPoint(UndoType.GroupMove)
                            Destination.Element.Groups.Add(Source.Group)
                            Source.Element.Groups.RemoveAt(Source.Element.Groups.IndexOf(Source.Group))
                        End If
                    Case DragDropStructure.LowestLevelValues.Element
                        If Destination.Element IsNot Source.Element Then
                            MakeUndoPoint(UndoType.ElMove)
                            Project.ProjectElements.ExchangeIndex(GetElementIndex(RMP), Project.ProjectElements.IndexOf(Source.Element))
                        End If
                End Select
            Case DragDropStructure.LowestLevelValues.Project
                If Source.Element IsNot Nothing Then
                    Dim ProjectDestination As L3DObjectsLibrary.Project = Project
                    Dim FollowingRectangle As System.Drawing.Rectangle
                    Dim UpSection As Drawing.Rectangle
                    Dim DownSection As Drawing.Rectangle
                    Dim ElementToMove As L3DObjectsLibrary.ProjectElement = Source.Element
                    For Each Element As L3DObjectsLibrary.ProjectElement In Project.ProjectElements
                        FollowingRectangle = New Drawing.Rectangle(0, GetElementUpSection(Element).Top, Width, GetElementUpSection(Element).Height + GetElementDownSection(Element).Height)
                        If FollowingRectangle.Contains(RMP) Then
                            If Element IsNot Source.Element Then
                                MakeUndoPoint(UndoType.ElMove)
                                UpSection = GetElementUpSection(Element)
                                DownSection = GetElementDownSection(Element)
                                Dim SIndex As Integer = Project.ProjectElements.IndexOf(Source.Element)
                                Dim DIndex As Integer = Project.ProjectElements.IndexOf(Element)
                                If UpSection.Contains(RMP) And DIndex > SIndex Then
                                    DIndex = DIndex - 1
                                ElseIf DownSection.Contains(RMP) And SIndex > DIndex Then
                                    DIndex = DIndex + 1
                                End If
                                Project.ProjectElements.MoveToIndex(SIndex, DIndex)
                                Exit For
                            End If
                        End If
                    Next
                End If
        End Select
    End Sub
    Private Sub DropElement(ByVal Source As L3DObjectsLibrary.ProjectElement)
        MakeUndoPoint(UndoType.ElAdd)
        Dim ProjectDestination As L3DObjectsLibrary.Project = Project
        Dim FollowingRectangle As System.Drawing.Rectangle
        If Project.ProjectElements.Count = 0 Then
            Project.ProjectElements.Add(Source)
        Else
            For Each Element As L3DObjectsLibrary.ProjectElement In Project.ProjectElements
                FollowingRectangle = GetElementRectangle(Element)
                If PointToClient(MousePosition).Y < (FollowingRectangle.Top + FollowingRectangle.Height / 2) Then
                    Project.ProjectElements.Insert(Project.ProjectElements.IndexOf(Element), Source)
                    Exit For
                ElseIf Project.ProjectElements.IndexOf(Element) = Project.ProjectElements.Count - 1 And (PointToClient(MousePosition).Y > (FollowingRectangle.Top + FollowingRectangle.Height / 2)) Then
                    Project.ProjectElements.Add(Source)
                    Exit For
                End If
            Next
        End If

    End Sub
    Private Sub DropGroup(ByVal Source As L3DObjectsLibrary.Group)
        Dim Destination As DragDropStructure = GetObjectUnderPoint(RMP)
        Select Case Destination.LowestLevelObject
            Case DragDropStructure.LowestLevelValues.Element, DragDropStructure.LowestLevelValues.Group, DragDropStructure.LowestLevelValues.Car
                MakeUndoPoint(UndoType.GroupAdd)
                Dim Element As L3DObjectsLibrary.ProjectElement = Destination.Element
                If Element.ElementType = ElementTypeValue.L3DPhase Or Element.ElementType = ElementTypeValue.L3DMixed Then
                    Element.Groups.Add(Source)
                End If
            Case DragDropStructure.LowestLevelValues.Project
                MakeUndoPoint(UndoType.ElAdd)
                Dim NewElement As New L3DObjectsLibrary.ProjectElement
                NewElement.Groups.Add(Source)
                DropElement(NewElement)
        End Select
    End Sub
    Private Sub DropCar(ByVal Source As L3DObjectsLibrary.Car)
        Dim Destination As DragDropStructure = GetObjectUnderPoint(RMP)
        Select Case Destination.LowestLevelObject
            Case DragDropStructure.LowestLevelValues.Element
                MakeUndoPoint(UndoType.GroupAdd)
                Dim Element As L3DObjectsLibrary.ProjectElement = Destination.Element
                If Element.ElementType = ElementTypeValue.L3DPhase Or Element.ElementType = ElementTypeValue.L3DMixed Then
                    Element.Groups.First.Cars.Add(Source)
                End If
            Case DragDropStructure.LowestLevelValues.Group, DragDropStructure.LowestLevelValues.Car
                MakeUndoPoint(UndoType.CarAdd)
                Dim Group As L3DObjectsLibrary.Group = Destination.Group
                Group.Cars.Add(Source)
            Case DragDropStructure.LowestLevelValues.Project
                MakeUndoPoint(UndoType.ElAdd)
                Dim NewElement As New L3DObjectsLibrary.ProjectElement
                Dim Group As New L3DObjectsLibrary.Group
                Group.Cars.Add(Source)
                NewElement.Groups.Add(Group)
                DropElement(NewElement)
        End Select
    End Sub
    Private Sub StartDragDropOperation()
        DragOperationStarted = True
        TimerRefresh.Interval = HiRefresh
        Dim Source As DragDropStructure = GetObjectUnderPoint(RMP)
        With Source
            Select Case .LowestLevelObject
                Case DragDropStructure.LowestLevelValues.Car
                    .MouseOffset = GetCarRectangle(Source.Car).Location - RMP
                Case DragDropStructure.LowestLevelValues.Group
                    .MouseOffset = GetGroupRectangle(Source.Group).Location - RMP
                Case DragDropStructure.LowestLevelValues.Element
                    .MouseOffset = GetElementRectangle(Source.Element).Location - RMP
            End Select
        End With
        DragObjectValue = Source
        Me.DoDragDrop(Source, Windows.Forms.DragDropEffects.Move)
    End Sub
    Private Sub StopDragDropOperation()
        DragOperationStarted = False
        DragObjectValue = Nothing
        TimerRefresh.Interval = StdRefresh
    End Sub
    Private Sub Me_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragOver
        Dim Source As New Object
        MakeEditorsInvisible()
        e.Effect = Windows.Forms.DragDropEffects.All
        DragOperationStarted = True
        If e.Data.GetDataPresent(GetType(DragDropStructure)) = True Then
            Source = e.Data.GetData(GetType(DragDropStructure))
        ElseIf e.Data.GetDataPresent(GetType(L3DObjectsLibrary.ProjectElement)) = True Then
            Source = e.Data.GetData(GetType(L3DObjectsLibrary.ProjectElement))
        ElseIf e.Data.GetDataPresent(GetType(L3DObjectsLibrary.Group)) = True Then
            Source = e.Data.GetData(GetType(L3DObjectsLibrary.Group))
        ElseIf e.Data.GetDataPresent(GetType(L3DObjectsLibrary.Car)) = True Then
            Source = e.Data.GetData(GetType(L3DObjectsLibrary.Car))
        End If
        DragObjectValue = Source
        TimerRefresh.Interval = 10
    End Sub
    Private Sub Me_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragDrop
        Dim Source As Object
        StopDragDropOperation()
        If e.Data.GetDataPresent(GetType(DragDropStructure)) = True Then
            RaiseEvent QueryChange(Me, New QueryChangeEventArgs)
            Source = e.Data.GetData(GetType(DragDropStructure))
            DropDragDropStructure(CType(Source, DragDropStructure))
        ElseIf e.Data.GetDataPresent(GetType(L3DObjectsLibrary.ProjectElement)) = True Then
            Source = e.Data.GetData(GetType(L3DObjectsLibrary.ProjectElement))
            DropElement(CType(Source, L3DObjectsLibrary.ProjectElement))
        ElseIf e.Data.GetDataPresent(GetType(L3DObjectsLibrary.Group)) = True Then
            Source = e.Data.GetData(GetType(L3DObjectsLibrary.Group))
            DropGroup(CType(Source, L3DObjectsLibrary.Group))
        ElseIf e.Data.GetDataPresent(GetType(L3DObjectsLibrary.Car)) = True Then
            Source = e.Data.GetData(GetType(L3DObjectsLibrary.Car))
            DropCar(CType(Source, L3DObjectsLibrary.Car))
        End If
    End Sub
#End Region
#Region "GRAPHICS MANAGEMENT"
    Private Function GetElementRectangle(ByVal Element As L3DObjectsLibrary.ProjectElement) As System.Drawing.Rectangle
        Dim RSize As New Drawing.Size
        Dim RLoc As New Drawing.Point
        If Element IsNot Nothing Then
            RLoc = ComputeElementLocation(Element)
        Else
            RLoc = New Drawing.Point(0, 0)
        End If
        RSize = ComputeElementSize(Element)
        Dim Result As New System.Drawing.Rectangle(RLoc, RSize)
        Return Result
    End Function
    Private Function GetElementUpSection(ByVal El As ProjectElement) As Drawing.Rectangle
        Dim Rect = GetElementRectangle(El)
        With Rect
            Return New Drawing.Rectangle(0, .Top - ElementDistance / 2, Width, .Height / 2 + ElementDistance / 2)
        End With
    End Function
    Private Function GetElementDownSection(ByVal El As ProjectElement) As Drawing.Rectangle
        Dim Rect = GetElementRectangle(El)
        With Rect
            If .Height = 0 Then
                Return New Drawing.Rectangle(0, .Top + .Height / 2, Width, 0)
            ElseIf El Is Project.ProjectElements.Last Then
                Return New Drawing.Rectangle(0, .Top + .Height / 2, Width, Height - .Top - .Height / 2)
            Else
                Return New Drawing.Rectangle(0, .Top + .Height / 2, Width, .Height / 2 + ElementDistance / 2)
            End If
        End With
    End Function

    Private Function GetGroupRectangle(ByVal Group As L3DObjectsLibrary.Group) As System.Drawing.Rectangle
        Dim GSiz As New Drawing.Size
        Dim GLoc As Drawing.Point
        Dim ElRect As New System.Drawing.Rectangle
        Dim El As ProjectElement = Project.GetElementFromGroup(Group)
        With GLoc
            If El IsNot Nothing Then
                Dim GroupIndex As Integer = El.Groups.IndexOf(Group)
                ElRect = GetElementRectangle(El)
                .X = ElRect.Left + L3DObjectsLibrary.L3DGraphics.GroupMinLeft
                .Y = ElRect.Top + L3DObjectsLibrary.L3DGraphics.GroupMinTop + GroupIndex * (L3DObjectsLibrary.L3DGraphics.GroupHeight + L3DObjectsLibrary.L3DGraphics.GroupDistance)
            Else
                .X = 0
                .Y = 0
            End If
        End With
        With GSiz
            .Width = Group.Cars.Count * (L3DGraphics.CarWidth + L3DGraphics.CarDistance) + 2 * L3DGraphics.CarMinLeft
            .Height = L3DObjectsLibrary.L3DGraphics.GroupHeight
        End With
        Dim ResultRect As New System.Drawing.Rectangle(GLoc, GSiz)
        Return ResultRect
    End Function
    Private Function GetCarRectangle(ByVal Car As L3DObjectsLibrary.Car) As System.Drawing.Rectangle
        Dim RLoc As Drawing.Point
        Dim RSiz As Drawing.Size
        Dim Group As L3DObjectsLibrary.Group = Project.GetGroupFromCar(Car)
        With RLoc
            If Group IsNot Nothing Then
                Dim CarIndex As Integer = Group.Cars.IndexOf(Car)
                Dim GroupRectangle As System.Drawing.Rectangle = GetGroupRectangle(Group)
                .X = GroupRectangle.Left + L3DObjectsLibrary.L3DGraphics.CarMinLeft + CarIndex * (L3DObjectsLibrary.L3DGraphics.CarWidth + L3DObjectsLibrary.L3DGraphics.CarDistance)
                .Y = GroupRectangle.Top + L3DObjectsLibrary.L3DGraphics.CarMinTop
            Else
                .X = 0
                .Y = 0
            End If
        End With
        With RSiz
            .Width = L3DObjectsLibrary.L3DGraphics.CarWidth
            .Height = L3DObjectsLibrary.L3DGraphics.CarHeight
        End With
        Dim Result As New System.Drawing.Rectangle(RLoc, RSiz)
        Return Result
    End Function
    Private Sub DrawElement(ByVal Graph As System.Drawing.Graphics, ByVal Element As L3DObjectsLibrary.ProjectElement, Optional ByVal Location As System.Drawing.Point = Nothing, Optional ByVal Alpha As Integer = 255)
        Dim ElementRect As System.Drawing.Rectangle = GetElementRectangle(Element)
        Dim ElementOrigRect As Drawing.Rectangle = GetElementRectangle(Element)
        Dim ElColor As Drawing.Color = Drawing.Color.FromArgb(Alpha, Drawing.Color.LightBlue)
        Dim GRect As System.Drawing.Rectangle
        If Location <> Nothing Then
            ElementRect.Location = Location
        End If
        Dim ElementNamePosition As Integer = ElementRect.Bottom - 20
        If Element.ElementType = ElementTypeValue.L3DPhase Then
            If ElementRect.Contains(RMP) Then
                VMGenLibrary.Graphics.DrawRoundedRectangle(Graph, BoldSelectionPen, ElementRect, New System.Drawing.Size(20, 20), ElColor)
            Else
                VMGenLibrary.Graphics.DrawRoundedRectangle(Graph, LightBasePen, ElementRect, New System.Drawing.Size(20, 20), ElColor)
            End If
            For Each Group As L3DObjectsLibrary.Group In Element.Groups
                GRect = GetGroupRectangle(Group)
                If GRect.Location = Nothing Then
                    GRect.Location = ElementRect.Location + GroupElementOffset
                Else
                    GRect.Location = GRect.Location + (ElementRect.Location - ElementOrigRect.Location)
                End If
                DrawGroup(Graph, Group, GRect.Location, Alpha)
            Next
            System.Windows.Forms.TextRenderer.DrawText(Graph, Element.Name, _
                    New System.Drawing.Font(Me.Font.FontFamily, 10, Drawing.FontStyle.Bold), _
                    New System.Drawing.Rectangle(ElementRect.Left, ElementNamePosition, ElementRect.Width, 20), _
                    System.Drawing.Color.FromArgb(Alpha, Drawing.Color.Black), _
                    System.Drawing.Color.Transparent, _
                    (Windows.Forms.TextFormatFlags.VerticalCenter + Windows.Forms.TextFormatFlags.HorizontalCenter))
        ElseIf Element.ElementType = ElementTypeValue.L3DMilestone Then
            If Element.Milestones.First.ShowInPlan = True Then
                DrawMilestone(Graph, Element, Location, Alpha)
            End If
        End If
    End Sub
    Private Sub DrawGroup(ByVal Graph As System.Drawing.Graphics, ByVal Group As L3DObjectsLibrary.Group, Optional ByVal Location As System.Drawing.Point = Nothing, Optional ByVal Alpha As Integer = 255)
        Dim GroupRect As System.Drawing.Rectangle = GetGroupRectangle(Group)
        Dim GroupRectOrig As System.Drawing.Rectangle = GetGroupRectangle(Group)
        Dim GroupColor As Drawing.Color = Drawing.Color.FromArgb(Alpha, Drawing.Color.AliceBlue)
        Dim CRect As Drawing.Rectangle
        If Location <> Nothing Then
            GroupRect.Location = Location
        End If
        If GroupRect.Contains(RMP) Then
            VMGenLibrary.Graphics.DrawRoundedRectangle(Graph, BoldSelectionPen, GroupRect, New System.Drawing.Size(20, 20), GroupColor)
        Else
            VMGenLibrary.Graphics.DrawRoundedRectangle(Graph, LightBasePen, GroupRect, New System.Drawing.Size(20, 20), GroupColor)
        End If
        For Each Car As L3DObjectsLibrary.Car In Group.Cars
            CRect = GetCarRectangle(Car)
            If CRect.Location = Nothing Then
                CRect.Location = GroupRect.Location + CarGroupOffset
            Else
                CRect.Location = CRect.Location + (GroupRect.Location - GroupRectOrig.Location)
            End If
            DrawCar(Graph, Car, CRect.Location, Alpha)
        Next
    End Sub
    Private Sub DrawCar(ByVal Graph As System.Drawing.Graphics, ByVal Car As L3DObjectsLibrary.Car, Optional ByVal Location As System.Drawing.Point = Nothing, Optional ByVal Alpha As Integer = 255)
        Dim CarRectangle As Drawing.Rectangle = GetCarRectangle(Car)
        If Location <> Nothing Then
            CarRectangle.Location = Location
        End If
        Dim TextRectangle As New System.Drawing.Rectangle(CarRectangle.Left, CarRectangle.Bottom - 5, CarRectangle.Width, 10)
        Dim TrianglePoints(2) As System.Drawing.PointF
        Dim CircleDiameter = CarRectangle.Height
        Dim CircleRadius = CircleDiameter / 2
        Dim Center As New System.Drawing.Point(CarRectangle.Left + CarWidth / 2, CarRectangle.Top + CircleRadius - 5)
        Dim PointsAngle(3) As Single
        Dim PolygonRotation As Single = -Math.PI * 1 / 6
        PointsAngle(0) = 0 + PolygonRotation
        PointsAngle(1) = Math.PI * 2 / 3 + PolygonRotation
        PointsAngle(2) = Math.PI * 4 / 3 + PolygonRotation
        For Edge = 0 To 2
            TrianglePoints(Edge) = New System.Drawing.PointF(Center.X - CircleRadius * Math.Cos(PointsAngle(Edge)), Center.Y + CircleRadius * Math.Sin(PointsAngle(Edge)))
        Next
        Dim CarPath As New System.Drawing.Drawing2D.GraphicsPath
        CarPath.AddPolygon(TrianglePoints)
        Graph.FillPath(New System.Drawing.SolidBrush(Drawing.Color.FromArgb(Alpha, Drawing.Color.Red)), CarPath)
        System.Windows.Forms.TextRenderer.DrawText(Graph, Car.Name, _
                            New System.Drawing.Font(Me.Font.FontFamily, 6), _
                            TextRectangle, _
                            System.Drawing.Color.FromArgb(Alpha, Drawing.Color.Black), _
                            System.Drawing.Color.Transparent, _
                            (Windows.Forms.TextFormatFlags.VerticalCenter + Windows.Forms.TextFormatFlags.HorizontalCenter))
        If CarRectangle.Contains(RMP) Then
            Graph.DrawPath(BoldSelectionPen, CarPath)
        Else
            Graph.DrawPath(LightBasePen, CarPath)
        End If
    End Sub
    Private Sub DrawMilestone(ByVal Graph As System.Drawing.Graphics, ByVal Element As L3DObjectsLibrary.ProjectElement, Optional ByVal Location As System.Drawing.Point = Nothing, Optional ByVal Alpha As Integer = 255)
        Dim MilestoneRect As System.Drawing.Rectangle = GetElementRectangle(Element)
        If Location <> Nothing Then
            MilestoneRect.Location = Location
        End If
        Dim SymbolLeft As Integer = MilestoneRect.Left + MilestoneRect.Width / 2 - L3DObjectsLibrary.L3DGraphics.MilestoneSymbolWidth / 2
        Dim SymbolTop As Integer = MilestoneRect.Top + L3DObjectsLibrary.L3DGraphics.MilestoneSymbolMargin
        Dim MilestoneNamePosition As Integer = MilestoneRect.Bottom - L3DObjectsLibrary.L3DGraphics.MilestoneNameHeight - L3DObjectsLibrary.L3DGraphics.MilestoneSymbolMargin
        Dim MyBrush As New System.Drawing.SolidBrush(MilestoneBaseColor)
        Dim Milestone As L3DObjectsLibrary.Milestone = Element.Milestones.First
        With Milestone
            If .SpecialID = MilestoneConstantValues.SpecialIDValues.DAP Then
                .Name = "DAP"
                .Editable = False
                MyBrush = New System.Drawing.SolidBrush(MilestoneDapColor)
            ElseIf Milestone.SpecialID = MilestoneConstantValues.SpecialIDValues.SOP Then
                .Name = "SOP"
                .Editable = False
                MyBrush = New System.Drawing.SolidBrush(MilestoneSopColor)
            Else
                .Editable = True
            End If
        End With
        Dim SymbolContainer As New System.Drawing.Rectangle(SymbolLeft, SymbolTop, L3DObjectsLibrary.L3DGraphics.MilestoneSymbolWidth, L3DObjectsLibrary.L3DGraphics.MilestoneSymbolHeight)
        Dim MyPath As New System.Drawing.Drawing2D.GraphicsPath
        MyPath.AddArc(SymbolContainer, 0, 360)
        Graph.FillPath(MyBrush, MyPath)
        Graph.DrawPath(LightBasePen, MyPath)
        System.Windows.Forms.TextRenderer.DrawText(Graph, Milestone.Name, _
                    New System.Drawing.Font(Me.Font.FontFamily, 10, Drawing.FontStyle.Bold), _
                    New System.Drawing.Rectangle(MilestoneRect.Left, MilestoneNamePosition, L3DObjectsLibrary.MilestoneWidth, L3DObjectsLibrary.L3DGraphics.MilestoneNameHeight), _
                    System.Drawing.Color.FromArgb(Alpha, Drawing.Color.Black), _
                    System.Drawing.Color.Transparent, _
                    (Windows.Forms.TextFormatFlags.VerticalCenter + Windows.Forms.TextFormatFlags.HorizontalCenter))
        If MilestoneRect.Contains(RMP) Then
            VMGenLibrary.Graphics.DrawRoundedRectangle(Graph, BoldSelectionPen, MilestoneRect, New System.Drawing.Size(20, 20), Drawing.Color.Transparent)
        End If
    End Sub
    Private Sub DrawCursor(ByVal Graph As System.Drawing.Graphics)
        If IsNothing(DragObjectValue) = False And ActiveRectangle.Contains(RMP) Then
            Select Case DragObjectValue.GetType
                Case GetType(DragDropStructure)
                    Dim DDStuct As DragDropStructure = CType(DragObjectValue, DragDropStructure)
                    DrawCursorDDStructure(Graph, DDStuct)
                Case GetType(L3DObjectsLibrary.ProjectElement)
                    Dim El As L3DObjectsLibrary.ProjectElement = CType(DragObjectValue, L3DObjectsLibrary.ProjectElement)
                    DrawCursorElement(Graph, El)
                Case GetType(L3DObjectsLibrary.Group)
                    Dim Grp As L3DObjectsLibrary.Group = CType(DragObjectValue, L3DObjectsLibrary.Group)
                    DrawCursorGroup(Graph, Grp)
                Case GetType(L3DObjectsLibrary.Car)
                    Dim Car As L3DObjectsLibrary.Car = CType(DragObjectValue, L3DObjectsLibrary.Car)
                    DrawCursorCar(Graph, Car)
            End Select
        Else
            Dim DDStruc As DragDropStructure = GetObjectUnderPoint(RMP)
            If DDStruc.LowestLevelObject = DragDropStructure.LowestLevelValues.Car Then
                DrawToolTip(Graph, RMP, DDStruc.Car.Name)
            End If
        End If
    End Sub
    Private Sub DrawCursorDDStructure(ByVal Graph As System.Drawing.Graphics, ByVal DDStruct As DragDropStructure)
        With DDStruct
            Select Case .LowestLevelObject
                Case DragDropStructure.LowestLevelValues.Car
                    Dim CarRectangle As System.Drawing.Rectangle = GetCarRectangle(.Car)
                    DrawCar(Graph, .Car, RMP + .MouseOffset, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
                Case DragDropStructure.LowestLevelValues.Group
                    DrawGroup(Graph, .Group, RMP + .MouseOffset, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
                Case DragDropStructure.LowestLevelValues.Element
                    If Math.Abs(RMP.Y - BufferedMousePosition.Y) < L3DGraphics.TranslateElementOffset Then
                        TranslateElement = True
                        Dim HorDiff As Integer = RMP.X - BufferedMousePosition.X
                        Dim CursRect As System.Drawing.Rectangle = GetElementRectangle(.Element)
                        Dim CursLoc As New System.Drawing.Point(CursRect.X + HorDiff, CursRect.Y)
                        Dim NewDate As Date
                        If .Element.ElementType = ElementTypeValue.L3DPhase Or .Element.ElementType = ElementTypeValue.L3DMixed Then
                            DrawElement(Graph, .Element, CursLoc, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
                            NewDate = ComputeDateOnLeft(CursLoc.X)
                        ElseIf .Element.ElementType = ElementTypeValue.L3DMilestone Then
                            DrawMilestone(Graph, .Element, CursLoc, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
                            NewDate = ComputeDateOnLeft(CursLoc.X + CursRect.Width / 2)
                        End If
                        DrawToolTip(Graph, RMP, Format(NewDate, "dd MMMM yyyy"))
                    Else
                        TranslateElement = False
                        If .Element.ElementType = ElementTypeValue.L3DPhase Or .Element.ElementType = ElementTypeValue.L3DMixed Then
                            DrawElement(Graph, .Element, RMP + .MouseOffset, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
                        ElseIf .Element.ElementType = ElementTypeValue.L3DMilestone Then
                            DrawMilestone(Graph, .Element, RMP + .MouseOffset, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
                        End If
                    End If
            End Select
        End With
    End Sub
    Private Sub DrawCursorElement(ByVal Graph As Drawing.Graphics, ByVal El As L3DObjectsLibrary.ProjectElement)
        Dim Location As New Drawing.Point
        If El.ElementType = ElementTypeValue.L3DPhase Or El.ElementType = ElementTypeValue.L3DMixed Then
            Location = RMP
        Else
            Location = RMP - New Drawing.Point(MilestoneWidth / 2, 0)
        End If
        DrawElement(Graph, El, Location, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
    End Sub
    Private Sub DrawCursorGroup(ByVal Graph As Drawing.Graphics, ByVal Group As L3DObjectsLibrary.Group)
        DrawGroup(Graph, Group, RMP, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
    End Sub
    Private Sub DrawCursorCar(ByVal Graph As Drawing.Graphics, ByVal Car As L3DObjectsLibrary.Car)
        DrawCar(Graph, Car, RMP, L3DObjectsLibrary.L3DGraphics.AlphaCursor)
    End Sub
    Private Sub DrawDateStrip(ByVal Graph As System.Drawing.Graphics)
        Dim YRect As System.Drawing.Rectangle
        Dim Ysiz As New System.Drawing.Size(YearWidth, DateStripHeight)
        Dim Yloc As New System.Drawing.Point(0, 0)
        Dim MRect As New Drawing.RectangleF
        Dim MRectInt As New Drawing.Rectangle
        Dim Msiz As New Drawing.SizeF(MonthWidth, DateStripHeight)
        Dim Mloc As New Drawing.PointF(0, DateStripHeight)
        Dim MonthLabelFormat As New System.Drawing.StringFormat
        Dim RMP As Drawing.Point = Me.PointToClient(MousePosition)
        With MonthLabelFormat
            .Alignment = Drawing.StringAlignment.Center
            .LineAlignment = Drawing.StringAlignment.Center
        End With
        For NY = 0 To NumberOfYears
            With Yloc
                .X = NY * YearWidth - ScrollOffset.X
            End With
            YRect = New Drawing.Rectangle(Yloc, Ysiz)
            If RMP.X >= YRect.Left And RMP.X < YRect.Right And Me.ClientRectangle.Contains(RMP) Then
                Graph.FillRectangle(SelectionColor, YRect)
            Else
                Graph.FillRectangle(StdBackColor, YRect)
            End If
            Graph.DrawRectangle(YearLinePen, YRect)
            Graph.DrawString(Str(Project.FirstProjectYear + NY), Me.Font, Drawing.Brushes.Black, YRect, MonthLabelFormat)
            For NM = 0 To 11
                Mloc.X = Yloc.X + NM * MonthWidth
                MRect = New Drawing.RectangleF(Mloc, Msiz)
                MRectInt = Drawing.Rectangle.Round(MRect)
                If RMP.X >= MRect.Left And RMP.X < MRect.Right And Me.ClientRectangle.Contains(RMP) Then
                    Graph.FillRectangle(SelectionColor, MRect)
                Else
                    Graph.FillRectangle(StdBackColor, MRect)
                End If
                Graph.DrawRectangle(YearLinePen, MRectInt)
                Graph.DrawString(MonthName(NM + 1, True), Me.Font, Drawing.Brushes.Black, MRectInt, MonthLabelFormat)
            Next
        Next
    End Sub
    Private Sub DrawDateLines(ByVal Graph As System.Drawing.Graphics)
        Dim YSP As New Drawing.Point(0, 0)
        Dim YEP As New Drawing.Point(0, Height)
        Dim MSP As New Drawing.Point(0, 0)
        Dim MEP As New Drawing.Point(0, Height)
        Dim RMP As Drawing.Point = Me.PointToClient(MousePosition)
        For NY = 0 To NumberOfYears + 1
            YSP.X = NY * YearWidth - ScrollOffset.X
            YEP.X = YSP.X
            Graph.DrawLine(YearLinePen, YSP, YEP)
            If NY <= NumberOfYears Then
                For NM = 1 To 11
                    MSP.X = YSP.X + NM * MonthWidth
                    MEP.X = MSP.X
                    Graph.DrawLine(MonthLinePen, MSP, MEP)
                Next
            End If
        Next
    End Sub
    Private Sub DrawAll(ByVal Graph As System.Drawing.Graphics)
        Graph.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality
        Dim RMP As Drawing.Point = Me.PointToClient(MousePosition)
        If ScrollOffset.Y > 0 Then
            Dim AR As New Drawing.Rectangle(Width / 2 - 100, 50, 200, 200)
            DrawArrow(Graph, AR, Drawing.Color.AliceBlue, 0)
        End If
        For Each El As ProjectElement In Project.ProjectElements
            If ComputeLeftOnDate(El.MinDate) < 0 Then
                Dim AR As New Drawing.Rectangle(ActiveRectangle.Left + 10, Height / 2 - 100, 200, 200)
                DrawArrow(Graph, AR, Drawing.Color.AliceBlue, -90)
            End If
            If ComputeLeftOnDate(El.MaxDate) > ActiveRectangle.Right Then
                Dim AR As New Drawing.Rectangle(ActiveRectangle.Width - 200 - 10, Height / 2 - 100, 200, 200)
                DrawArrow(Graph, AR, Drawing.Color.AliceBlue, 90)
            End If
        Next
        DrawDateLines(Graph)
        For Each Element As L3DObjectsLibrary.ProjectElement In Project.ProjectElements
            DrawElement(Graph, Element)
        Next
        If DragOperationStarted = True Then
            Dim Y As Integer
            Dim LeftPoint As System.Drawing.Point
            Dim RightPoint As System.Drawing.Point
            Dim MouseOverRectangle As Boolean
            For Each Element As L3DObjectsLibrary.ProjectElement In Project.ProjectElements
                If GetElementRectangle(Element).Contains(RMP) Then
                    MouseOverRectangle = True
                    Exit For
                ElseIf GetElementUpSection(Element).Contains(RMP) Then
                    Y = GetElementRectangle(Element).Top - L3DObjectsLibrary.L3DGraphics.ElementDistance / 2
                    Exit For
                ElseIf GetElementDownSection(Element).Contains(RMP) Then
                    Y = GetElementRectangle(Element).Bottom + L3DObjectsLibrary.L3DGraphics.ElementDistance / 2
                    Exit For
                End If
            Next
            If MouseOverRectangle = False Then


                LeftPoint.X = 0
                RightPoint.X = Me.Width
                LeftPoint.Y = Y
                RightPoint.Y = Y
                Graph.DrawLine(BoldSelectionPen, LeftPoint, RightPoint)
            End If
        End If
        DrawDateStrip(Graph)
        DrawCursor(Graph)
    End Sub
    Private Sub DrawArrow(ByVal Graph As System.Drawing.Graphics, ByVal Rect As System.Drawing.Rectangle, ByVal Color As System.Drawing.Color, ByVal Angle As Single)
        Dim Pt(6) As System.Drawing.Point
        Pt(0).X = Rect.Left + Rect.Width / 2
        Pt(0).Y = Rect.Top
        Pt(1).X = Rect.Right
        Pt(1).Y = Rect.Top + Rect.Height / 2
        Pt(2).X = Pt(0).X + Rect.Width / 4
        Pt(2).Y = Pt(1).Y
        Pt(3).X = Pt(2).X
        Pt(3).Y = Rect.Bottom
        Pt(4).X = Pt(3).X - Rect.Width / 2
        Pt(4).Y = Pt(3).Y
        Pt(5).X = Pt(4).X
        Pt(5).Y = Pt(2).Y
        Pt(6).X = Rect.Left
        Pt(6).Y = Pt(1).Y
        Dim Path As New System.Drawing.Drawing2D.GraphicsPath
        With Path
            .AddPolygon(Pt)
        End With
        Dim Mat As New System.Drawing.Drawing2D.Matrix
        With Mat
            .RotateAt(Angle, New System.Drawing.Point(Pt(0).X, Rect.Top + Rect.Height / 2))
        End With
        Path.Transform(Mat)
        Dim Br As New System.Drawing.SolidBrush(Color)
        Graph.FillPath(Br, Path)
    End Sub
    Private Sub DrawToolTip(ByVal Graph As Drawing.Graphics, ByVal Location As Drawing.Point, ByVal Text As String)
        Dim TextRect As New System.Drawing.Rectangle(Location, New System.Drawing.Size(150, 20))
        Dim TxtFormat As New Drawing.StringFormat
        With TxtFormat
            .Alignment = Drawing.StringAlignment.Center
            .LineAlignment = Drawing.StringAlignment.Center
        End With
        VMGenLibrary.Graphics.DrawRoundedRectangle(Graph, LightBasePen, TextRect, New System.Drawing.Size(5, 5), Drawing.Color.LightYellow)
        Graph.DrawString(Text, _
                         New System.Drawing.Font(Me.Font.FontFamily, 10, Drawing.FontStyle.Regular), _
                         Drawing.Brushes.Black, _
                         TextRect, _
                         TxtFormat)
    End Sub
#End Region
#Region "UNDO REDO MANAGEMENT"
    Public Sub Undo()
        If UndoHistoryPosition > 0 Then
            If UndoHistoryPosition = UndoHistory.Count Then
                UndoHistory.Add(Project.Clone)
            End If
            UndoHistoryPosition = UndoHistoryPosition - 1
            SetProjectAfterUndoRedo()
            RaiseEvent UndoRedoPerformed(Me, UndoRedoValue.Undo)
        End If
    End Sub
    Public Sub Redo()
        If UndoHistoryPosition < UndoHistory.Count - 1 Then
            UndoHistoryPosition = UndoHistoryPosition + 1
            SetProjectAfterUndoRedo()
            If UndoHistoryPosition = UndoHistory.Count - 1 Then
                RemoveUndoHistoryExcess()
            End If
            RaiseEvent UndoRedoPerformed(Me, UndoRedoValue.Redo)
        End If
    End Sub
    Public Sub MakeUndoPoint(ByVal Type As UndoType)
        If UndoHistoryPosition < UndoHistory.Count Then
            RemoveUndoHistoryExcess()
        End If
        Dim PrClone As Project = Me.Project.Clone
        UndoHistory.Add(PrClone)
        UndoHistoryPositionValue = UndoHistoryPosition + 1
    End Sub
    Private Sub SetProjectAfterUndoRedo()
        Project = UndoHistory(UndoHistoryPosition)
        Editor.LinkedProject = Project
    End Sub
    Private Sub RemoveUndoHistoryExcess()
        Do Until UndoHistoryPosition = UndoHistory.Count
            UndoHistory.RemoveAt(UndoHistory.Count - 1)
        Loop
    End Sub
#End Region
#Region "EVENTS MANAGEMENT"
    Private Sub Me_MouseDown(ByVal sender As Object, ByVal e As Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        BufferedMousePosition = RMP
    End Sub
    Private Sub Me_Click(ByVal sender As Object, ByVal e As Windows.Forms.MouseEventArgs) Handles Me.Click
        TimerClick.Start()
    End Sub
    Private Sub Me_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.DoubleClick
        TimerClick.Stop()
        Dim Source As DragDropStructure = GetObjectUnderPoint(RMP)
        If Source.LowestLevelObject = DragDropStructure.LowestLevelValues.Car Then
            MakeUndoPoint(UndoType.CarAdd)
            Dim Car As L3DObjectsLibrary.Car = Source.Car.Clone
            Source.Group.Cars.Add(Car)
        ElseIf Source.LowestLevelObject = DragDropStructure.LowestLevelValues.Group Then
            MakeUndoPoint(UndoType.GroupAdd)
            Dim Gr As L3DObjectsLibrary.Group = Source.Group.Clone
            Dim Ind As Integer = Source.Element.Groups.IndexOf(Source.Group)
            Source.Element.Groups.Insert(Ind, Gr)
        ElseIf Source.LowestLevelObject = DragDropStructure.LowestLevelValues.Element Then
            If Source.Element.ElementType = ElementTypeValue.L3DMilestone Then
                If Source.Element.Milestones.First.Editable = False Then
                    Exit Sub
                End If
            End If
            MakeUndoPoint(UndoType.ElAdd)
            Dim El As L3DObjectsLibrary.ProjectElement = Source.Element.Clone
            Dim Ind As Integer = Source.Project.ProjectElements.IndexOf(Source.Element)
            Source.Project.ProjectElements.Insert(Ind, El)
        End If
        Me.Invalidate()
    End Sub
    Private Sub Me_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove, CarEditor.MouseMove, MilestoneEditor.MouseMove, ElementEditor.MouseMove
        If e.Button = Windows.Forms.MouseButtons.None Then
            StopDragDropOperation()
        ElseIf e.Button = Windows.Forms.MouseButtons.Left And DragOperationStarted = False Then
            StartDragDropOperation()
        End If
    End Sub
    Private Sub Me_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
        With Editor
            .Visible = False
            .LinkedProject = Project
            .Parent = Me
            .BackColor = Drawing.Color.Transparent
        End With
        TimerClick.Interval = System.Windows.Forms.SystemInformation.DoubleClickTime
        TimerRefresh.Start()
    End Sub
    Private Sub Me_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
        With VScrollBar
            .Location = New Drawing.Point(ActiveRectangle.Right, ActiveRectangle.Top)
            .Size = New Drawing.Size(Padding.Right, ActiveRectangle.Height)
        End With
        With HScrollBar
            .Location = New Drawing.Point(ActiveRectangle.Left, ActiveRectangle.Bottom)
            .Size = New Drawing.Size(ActiveRectangle.Width, Padding.Bottom)
        End With
    End Sub
    Private Sub Me_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        DrawAll(e.Graphics)
    End Sub
    Private Sub TimerClick_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerClick.Tick
        TimerClick.Stop()
        CarEditor.Visible = False
        ElementEditor.Visible = False
        MilestoneEditor.Visible = False
        Dim Target As DragDropStructure = GetObjectUnderPoint(BufferedMousePosition)
        With Target
            Select Case .LowestLevelObject
                Case DragDropStructure.LowestLevelValues.Element
                    If .Element.ElementType = ElementTypeValue.L3DPhase Then
                        With ElementEditor
                            .Location = BufferedMousePosition
                            .LinkedElement = Target.Element
                            .Visible = Not (.Visible)
                        End With
                    ElseIf .Element.ElementType = ElementTypeValue.L3DMilestone And .Element.Milestones.First.Editable = True Then
                        With MilestoneEditor
                            .Location = BufferedMousePosition
                            .LinkedMilestone = Target.Element.Milestones.First
                            .Visible = Not (.Visible)
                        End With
                    End If
                Case DragDropStructure.LowestLevelValues.Car
                    With CarEditor
                        .Location = BufferedMousePosition
                        .LinkedCar = Target.Car
                        .Visible = Not (.Visible)
                    End With
                Case DragDropStructure.LowestLevelValues.Project

            End Select
        End With
    End Sub
    Private Sub TimerRefresh_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerRefresh.Tick
        Dim DrawLocation As New System.Drawing.Point(0, 0)
        Dim DrawSize As New System.Drawing.Size(Width, 40)
        Dim DrawRect As New System.Drawing.Rectangle(DrawLocation, DrawSize)
        If MilestoneEditor.Visible = True Or CarEditor.Visible = True Or Editor.Visible = True Then
            Me.Invalidate(DrawRect)
        Else
            Refresh()
        End If
        If ActiveRectangle.Contains(RMP) Then
            If DragOperationStarted = False Then
                TimerRefresh.Interval = StdRefresh
            Else
                TimerRefresh.Interval = HiRefresh
            End If
        Else
            TimerRefresh.Interval = LowRefresh
        End If
    End Sub
    Private Sub Editor_CloseRequest(ByVal sender As Object, ByVal CloseStatus As Microsoft.VisualBasic.MsgBoxResult) Handles CarEditor.CloseRequest, ElementEditor.CloseRequest, MilestoneEditor.CloseRequest, ProjectEditor.CloseRequest
        If CloseStatus = MsgBoxResult.Ok Then
            Select Case sender.GetType
                Case GetType(ProjectEditor)
                    MakeUndoPoint(UndoType.ProjectEdit)
                Case GetType(ProjectElementEditor)
                    MakeUndoPoint(UndoType.ElEdit)
                Case GetType(MilestoneEditor)
                    MakeUndoPoint(UndoType.ElEdit)
                Case GetType(CarEditor)
                    MakeUndoPoint(UndoType.CarEdit)
            End Select
            Project.OnQueryChange()
        End If
        MakeEditorsInvisible()
    End Sub
    Private Sub ScrollBar_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) Handles HScrollBar.Scroll, VScrollBar.Scroll
        Me.Invalidate(Me.ClientRectangle)
    End Sub
    Private Sub Project_QueryChange(ByVal sender As Object, ByVal e As QueryChangeEventArgs) Handles ProjectValue.QueryChange
        RaiseEvent QueryChange(Me, e)
    End Sub
#End Region

End Class
